﻿using Sidvall.Collections;
using Sidvall.UI.Entities;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace Sidvall.UI.ViewModels
{
    public class TreeControlViewModel : ControlViewModelBase
    {
        #region Public Members

        public event System.EventHandler SelectedItemsChanged;
        public ITreeItemManager TreeItemManager { get; set; }

        #region ActiveTreeItem

        private TreeItem _ActiveTreeItem;
        public TreeItem ActiveTreeItem
        {
            get
            {
                return _ActiveTreeItem;
            }
            set
            {
                _ActiveTreeItem = value;
                RaisePropertyChanged(nameof(ActiveTreeItem));
            }
        }

        #endregion
        #region AllowMultipleSelections

        private bool _AllowMultipleSelections;
        public bool AllowMultipleSelections
        {
            get
            {
                return _AllowMultipleSelections;
            }
            set
            {
                _AllowMultipleSelections = value;
                RaisePropertyChanged(nameof(AllowMultipleSelections));
            }
        }

        #endregion
        #region OnlyAllowChildSelection

        private bool _OnlyAllowChildSelection;
        public bool OnlyAllowChildSelection
        {
            get
            {
                return _OnlyAllowChildSelection;
            }
            set
            {
                _OnlyAllowChildSelection = value;
                RaisePropertyChanged(nameof(OnlyAllowChildSelection));
            }
        }

        #endregion
        #region ExpandAllNodes

        private bool _ExpandAllNodes;
        public bool ExpandAllNodes
        {
            get
            {
                return _ExpandAllNodes;
            }
            set
            {
                _ExpandAllNodes = value;
                RaisePropertyChanged(nameof(ExpandAllNodes));
            }
        }

        #endregion
        #region SelectedBehavior

        private TreeItemSelectedBehavior _SelectedBehavior;
        public TreeItemSelectedBehavior SelectedBehavior
        {
            get
            {
                return _SelectedBehavior;
            }
            set
            {
                _SelectedBehavior = value;
                RaisePropertyChanged(nameof(SelectedBehavior));
            }
        }

        #endregion
        #region SelectedItemsTextType

        private TreeItemNameType _SelectedItemsTextType;
        public TreeItemNameType SelectedItemsTextType
        {
            get
            {
                return _SelectedItemsTextType;
            }
            set
            {
                _SelectedItemsTextType = value;
                RaisePropertyChanged(nameof(SelectedItemsTextType));
            }
        }

        #endregion
        #region TreeItems

        private TreeItemCollection _TreeItems;
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
        public TreeItemCollection TreeItems
        {
            get
            {
                return _TreeItems;
            }
            set
            {
                _TreeItems = value;
                RaisePropertyChanged(nameof(TreeItems));
            }
        }

        #endregion
        #region SelectedItems

        private TreeItem[] _SelectedItems;
        public IEnumerable<TreeItem> SelectedItems
        {
            get
            {
                return _SelectedItems;
            }
        }

        #endregion
        #region SelectedItemIds

        private IEnumerable<string> _SelectedItemIds;
        public IEnumerable<string> SelectedItemIds
        {
            get
            {
                return _SelectedItemIds;
            }
            set
            {
                SetSelectedItemIds(value, true);
            }
        }

        #endregion
        #region SelectedItemsText

        public string SelectedItemsText
        {
            get
            {
                if (_SelectedItems == null)
                    return null;
                if (_SelectedItems.Length == 0)
                    return null;
                if (this.AllowMultipleSelections)
                {
                    if (_SelectedItems.Length > 3)
                        return _SelectedItems.Take(3).JoinToString(", ", true, o => TreeManager.GetName(o, this.SelectedItemsTextType)) + ", ...";
                    else
                        return _SelectedItems.JoinToString(", ", true, o => TreeManager.GetName(o, this.SelectedItemsTextType));
                }
                else
                {
                    return TreeManager.GetName(this.SelectedItems.FirstOrDefault(), this.SelectedItemsTextType);
                }
            }
        }

        #endregion
        #region SelectedValue

        public object SelectedValue
        {
            get
            {
                if (this.AllowMultipleSelections)
                    return null;
                if (this.SelectedItems?.FirstOrDefault() == null)
                    return null;
                return Sidvall.SystemContext.Current.CodeManager.GetPropertyValue(this.SelectedItems.FirstOrDefault().DataItem, this.SelectedValuePath);
            }
            set
            {
                if (this.AllowMultipleSelections)
                    return;
                var selectedItemIds = new List<string>();
                var item = Sidvall.UI.Entities.TreeManager.FindItemFromDataItemValue(this.TreeItems, value, this.SelectedValuePath);
                if (item != null)
                    selectedItemIds.Add(item.Id);
                this.SelectedItemIds = selectedItemIds;
            }
        }

        #endregion
        #region SelectedValuePath

        private string _SelectedValuePath;
        public string SelectedValuePath
        {
            get
            {
                return _SelectedValuePath;
            }
            set
            {
                if (_SelectedValuePath == value)
                    return;
                _SelectedValuePath = value;
                RaisePropertyChanged(nameof(SelectedValuePath));
            }
        }

        #endregion

        #region ApplySelectItems

        public bool ApplySelectItems()
        {
            if (this.AllowMultipleSelections)
            {
                SetSelectedItems(Sidvall.UI.Entities.TreeManager.FindItems(this.TreeItems, null, true, null, null, null), true);
                return true;
            }
            else
            {
                if (this.ActiveTreeItem?.IsSelectable == true)
                {
                    SetSelectedItem(this.ActiveTreeItem, true);
                    return true;
                }
                return false;
            }
        }

        #endregion
        #region ClearSelectItems

        public void ClearSelectItems()
        {
            Sidvall.UI.Entities.TreeManager.SetValues(this.TreeItems, null, null, false, null, null, true, true, false);
            RaisePropertyChanged(nameof(TreeItems));
            if (!this.AllowMultipleSelections)
                this.ActiveTreeItem = null;
            SetSelectedItems(null, true);
        }

        #endregion
        #region Initialize

        public void Initialize()
        {
            InitializeSelectedItems(true, true, false);
            if (this.OnlyAllowChildSelection)
            {
                var items = Sidvall.UI.Entities.TreeManager.FindItems(this.TreeItems, null, null, null, null, true);
                Sidvall.UI.Entities.TreeManager.SetValues(items, null, null, null, false, null, false, false, false);
            }
            Sidvall.UI.Entities.TreeManager.SetSelectedBehavior(this.TreeItems, this.SelectedBehavior, true, false, false);
            if (!this.AllowMultipleSelections)
                Sidvall.UI.Entities.TreeManager.SetFullNames(this.TreeItems, "/", true, false, false);
            _IsInitialized = true;
        }

        #endregion
        #region LoadChildItemsAsync

        public async Task LoadChildItemsAsync(TreeItem parent)
        {
            if ((parent?.IsLoaded == false) && (this.TreeItemManager != null))
            {
                var items = await this.TreeItemManager.GetChildItemsAsync(parent);
                parent.LoadChildItems(items);
                parent.IsLoaded = true;
            }
        }

        #endregion

        #endregion
        #region Private Members

        private bool _IsInitialized = false;

        #region InitializeSelectedItems

        private void InitializeSelectedItems(bool? isSelectable, bool? isVisible, bool raisePropertyChanged)
        {
            Sidvall.UI.Entities.TreeManager.SetValues(this.TreeItems, true, this.ExpandAllNodes, null, isSelectable, isVisible, true, raisePropertyChanged, false);
            Sidvall.UI.Entities.TreeManager.SetValues(this.TreeItems, null, null, true, null, null, true, raisePropertyChanged, false, this.SelectedItemIds);
            if (!this.ExpandAllNodes)
            {
                var items = Sidvall.UI.Entities.TreeManager.FindParents(this.TreeItems, this.SelectedItemIds, true);
                if (items.Any())
                    Sidvall.UI.Entities.TreeManager.SetValues(items, null, true, null, null, null, false, raisePropertyChanged, false);
            }
            _SelectedItems = Sidvall.UI.Entities.TreeManager.FindItems(this.TreeItems, this.SelectedItemIds);
            RaisePropertyChanged(nameof(SelectedItems));
            RaisePropertyChanged(nameof(SelectedItemsText));
            if (!this.AllowMultipleSelections)
            {
                this.ActiveTreeItem = _SelectedItems.FirstOrDefault();
            }
        }

        #endregion
        #region OnSelectedItemsChanged

        private void OnSelectedItemsChanged()
        {
            if (this.SelectedItemsChanged != null)
                this.SelectedItemsChanged(this, new System.EventArgs());
        }

        #endregion
        #region SetSelectedItem

        private void SetSelectedItem(TreeItem item, bool raiseSelectedItemsChanged)
        {
            SetSelectedItems(new TreeItem[] { item }, raiseSelectedItemsChanged);
        }

        #endregion
        #region SetSelectedItems

        private void SetSelectedItems(TreeItem[] items, bool raiseSelectedItemsChanged)
        {
            _SelectedItems = items;
            RaisePropertyChanged(nameof(SelectedItems));
            RaisePropertyChanged(nameof(SelectedItemsText));
            if (_SelectedItems != null)
            {
                SetSelectedItemIds(from o in _SelectedItems
                                   select o.Id, false);
            }
            else
            {
                SetSelectedItemIds(null, false);
            }
            if (raiseSelectedItemsChanged)
                OnSelectedItemsChanged();
        }

        #endregion
        #region SetSelectedItemIds

        private void SetSelectedItemIds(IEnumerable<string> ids, bool initializeSelectedItems)
        {
            _SelectedItemIds = ids;
            RaisePropertyChanged(nameof(SelectedItemIds));
            if (initializeSelectedItems)
            {
                if (!_IsInitialized)
                    return;
                InitializeSelectedItems(null, null, true);
            }
            if (!this.AllowMultipleSelections)
            {
                RaisePropertyChanged(nameof(SelectedValue));
            }
        }

        #endregion

        #endregion
        #region Constructors

        public TreeControlViewModel()
        {
        }

        #endregion
    }
}
